Skip to content

Added locations tracking - #22

Merged
arosha-w merged 6 commits into
mainfrom
isira
Feb 14, 2026
Merged

Added locations tracking #22
arosha-w merged 6 commits into
mainfrom
isira

Conversation

@iSiRaH

@iSiRaH iSiRaH commented Feb 13, 2026

Copy link
Copy Markdown
Collaborator
  • Added locations tracking
  • Store locations in database
  • Enhance refresh token logic
  • Added to fetch duty locations from backend

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds backend support for officer location tracking (persisting location points + retrieval APIs), introduces a duty-location lookup endpoint, and updates refresh-token handling to support validation + rotation.

Changes:

  • Added LocationPoint persistence model, DTO, repository, service, and controller endpoints for bulk upload + history/last-location retrieval.
  • Enhanced refresh token flow with findValidToken() + token rotation during /api/auth/refresh.
  • Added duty schedule location lookup (/api/duty-schedules/locations) backed by a distinct-location query with defaults.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
src/main/java/com/crimeLink/analyzer/service/impl/LocationServiceImpl.java Implements bulk save and history/last-location retrieval via repository
src/main/java/com/crimeLink/analyzer/service/LocationService.java Introduces location service interface
src/main/java/com/crimeLink/analyzer/controller/LocationController.java Adds endpoints for uploading and retrieving location data
src/main/java/com/crimeLink/analyzer/entity/LocationPoint.java New DB entity for storing officer location points (incl. JSON meta)
src/main/java/com/crimeLink/analyzer/dto/LocationPointDTO.java DTO record for mobile/client location payloads
src/main/java/com/crimeLink/analyzer/repository/LocationPointRepository.java Repository methods for history and last-location queries
src/main/java/com/crimeLink/analyzer/service/RefreshTokenService.java Adds validation + rotation support for refresh tokens
src/main/java/com/crimeLink/analyzer/repository/RefreshTokenRepository.java Adds fetch-join query to load refresh token with user
src/main/java/com/crimeLink/analyzer/controller/AuthController.java Updates refresh endpoint to rotate tokens and improve validation
src/main/java/com/crimeLink/analyzer/service/DutyScheduleService.java Adds DB-backed duty location list with defaults
src/main/java/com/crimeLink/analyzer/repository/DutyScheduleRepository.java Adds distinct location query
src/main/java/com/crimeLink/analyzer/controller/DutyScheduleController.java Exposes duty locations endpoint
src/main/java/com/crimeLink/analyzer/config/SecurityConfig.java Updates request matchers/authorization rules and CORS wiring
src/main/java/com/crimeLink/analyzer/config/JwtAuthenticationFilter.java Adjusts public-path bypass list and adds verbose debug logging

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/main/java/com/crimeLink/analyzer/config/SecurityConfig.java
Comment on lines +33 to +44
if (user == null) {
throw new RuntimeException("Unauthorized");
}

if (!"FieldOfficer".equalsIgnoreCase(user.getRole())) {
throw new RuntimeException("Only field officers can upload locations");
}

String officerBadgeNo = user.getBadgeNo();
if (officerBadgeNo == null || officerBadgeNo.isBlank()) {
throw new RuntimeException("Badge number missing");
}

Copilot AI Feb 13, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This controller throws generic RuntimeException for auth/authorization/validation failures (e.g., "Unauthorized", "Only field officers..."). Without a @ControllerAdvice mapping, these will become 500 responses. Use proper HTTP statuses (e.g., ResponseStatusException with 401/403/400, or @PreAuthorize + validation) so clients get correct error codes.

Copilot uses AI. Check for mistakes.
Comment on lines +20 to +29
import com.crimeLink.analyzer.service.impl.LocationServiceImpl;

import lombok.RequiredArgsConstructor;

@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class LocationController {
private final LocationServiceImpl service;

Copilot AI Feb 13, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LocationController injects the concrete LocationServiceImpl instead of the LocationService interface. Prefer depending on the interface to keep the controller decoupled and make testing/mocking easier.

Copilot uses AI. Check for mistakes.
Comment on lines 41 to +61
@@ -52,9 +53,12 @@ protected void doFilterInternal(
}

final String authHeader = request.getHeader("Authorization");
System.out.println("🔍 Auth Header: "
+ (authHeader != null ? authHeader.substring(0, Math.min(20, authHeader.length())) + "..." : "NULL"));

// ✅ No token -> continue (SecurityConfig will decide permit/deny)
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
System.out.println("❌ No Bearer token found");

Copilot AI Feb 13, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JwtAuthenticationFilter uses multiple System.out.println statements, including logging the Authorization header prefix. Avoid printing tokens/user data to stdout; use a logger with configurable levels (debug) and do not log any part of credentials/tokens in production logs.

Copilot uses AI. Check for mistakes.
Comment on lines +81 to +85

// 🔍 DEBUG: Log authentication success
System.out.println("✅ JWT Auth Success: " + userEmail);
System.out.println(" Authorities: " + userDetails.getAuthorities());
System.out.println(" Accessing: " + path);

Copilot AI Feb 13, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JwtAuthenticationFilter logs authentication success details (userEmail, authorities, path) to stdout. This is noisy and can leak security-relevant information. Switch to structured logging at debug level (or remove) and avoid logging authority sets for every request in normal operation.

Copilot uses AI. Check for mistakes.
Comment on lines +10 to +14
public void saveBulk(String officerBadgeNo, List<LocationPointDTO> points);

public List<LocationPoint> getHistory(String officerBadgeNo, Instant from, Instant to);

public LocationPoint getLastLocation(String officerBadgeNo);

Copilot AI Feb 13, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interface methods are implicitly public; the explicit "public" modifiers here are redundant noise. Consider removing them for consistency with typical Java interface style.

Suggested change
public void saveBulk(String officerBadgeNo, List<LocationPointDTO> points);
public List<LocationPoint> getHistory(String officerBadgeNo, Instant from, Instant to);
public LocationPoint getLastLocation(String officerBadgeNo);
void saveBulk(String officerBadgeNo, List<LocationPointDTO> points);
List<LocationPoint> getHistory(String officerBadgeNo, Instant from, Instant to);
LocationPoint getLastLocation(String officerBadgeNo);

Copilot uses AI. Check for mistakes.
// Allow duty schedule operations for OIC
.requestMatchers("/api/duty-schedules/**").hasRole("OIC")
// Public endpoints
.requestMatchers("/api/vehicle**").permitAll()

Copilot AI Feb 13, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SecurityConfig permits "/api/vehicle**", but the VehicleController is mapped to "/api/vehicles". As written, vehicle endpoints likely won’t be publicly accessible as intended (and may unexpectedly require authentication). Update the matcher to the correct path (e.g., "/api/vehicles/**").

Suggested change
.requestMatchers("/api/vehicle**").permitAll()
.requestMatchers("/api/vehicles/**").permitAll()

Copilot uses AI. Check for mistakes.
Comment on lines +55 to +61
.requestMatchers("/api/mobile/auth/**").permitAll()
.requestMatchers("/api/duties/**").permitAll()
.requestMatchers("/api/crime-reports/map").permitAll()

// Field Officer routes
.requestMatchers("/api/officers/me/**").hasRole("FieldOfficer")
.requestMatchers("/api/mobile/**").hasRole("FieldOfficer")

Copilot AI Feb 13, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"/api/duties/**" is configured as permitAll. These endpoints expose duty assignments by officerId and date, which is sensitive operational data; permitting unauthenticated access is a security risk. Consider requiring authentication (e.g., hasRole("FieldOfficer")/hasAnyRole(...)) and enforcing that a field officer can only query their own duties.

Copilot uses AI. Check for mistakes.
Comment on lines +54 to +60
System.out.println("📍 LocationController.history() called");
System.out.println(" Badge: " + officerBadgeNo);
System.out.println(" From: " + from + ", To: " + to);
System.out.println(" User: " + (user != null ? user.getEmail() : "NULL"));
System.out.println(" Role: " + (user != null ? user.getRole() : "NULL"));
System.out.println(" Authorities: " + (user != null ? user.getAuthorities() : "NULL"));
return service.getHistory(officerBadgeNo, from, to);

Copilot AI Feb 13, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This controller logs request details (including user info, badge numbers, and time ranges) via System.out.println. Please replace with structured logging (logger) at an appropriate level and remove the verbose debug output before merge to avoid leaking sensitive data and spamming logs.

Copilot uses AI. Check for mistakes.
Comment on lines +31 to +35
public void uploadMyLocations(@AuthenticationPrincipal User user, @RequestBody List<LocationPointDTO> points) {
System.out.println("Received locations: " + points.size()); // REMOVE: for testing
if (user == null) {
throw new RuntimeException("Unauthorized");
}

Copilot AI Feb 13, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uploadMyLocations() calls points.size() before validating the request body. If the client sends a null body, this will throw a NullPointerException and return 500. Add a null/empty check (and return 400) before accessing points.

Copilot uses AI. Check for mistakes.
@arosha-w
arosha-w merged commit f782bb7 into main Feb 14, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants